#include"operatornode.h"
#include<sstream>

OperatorNode::OperatorNode(_OPERATOR o, ExpressionNode * l, ExpressionNode * r) : op(o), left(l), right(r) {}
OperatorNode::OperatorNode(OperatorNode const & o) : op(o.op), left(o.left -> copy()), right(o.right -> copy()) {}
OperatorNode::~OperatorNode() {
	delete left;
	delete right;
}
	
ExpressionNode * OperatorNode::eval(ProgramNode const & state) const {
	ExpressionNode * le = left -> eval(state);
	ExpressionNode * re = right -> eval(state);
	IntegerNode l = le -> deint();
	IntegerNode r = re -> deint();
	int res = 0; bool u = (l.undef || r.undef);
	switch (op) {
		case _PLUS: res = l.val + r.val; break;
		case _MINUS: res = l.val - r.val; break;
		case _MULT: res = l.val * r.val; break;
		case _DIV: u = (r.val == 0); res = u ? 0 : (l.val / r.val); break;
		case _MOD: u = (r.val == 0); res = u ? 0 : (l.val % r.val); break;
		case _EQUAL: res = (l.val == r.val) ? 1 : 0; break;
		case _LT: res = (l.val < r.val) ? 1 : 0; break;
		case _GT: res = (l.val > r.val) ? 1 : 0; break;
		case _LE: res = (l.val <= r.val) ? 1 : 0; break;
		case _GE: res = (l.val >= r.val) ? 1 : 0; break;
		default: u = true;
	}
	delete le;
	delete re;
	return new IntegerNode(res, u);
}
	
bool OperatorNode::isFreeVar(VariableNode const & v) const {
	return (left -> isFreeVar(v)) || (right -> isFreeVar(v));
}

bool OperatorNode::isBoundVar(VariableNode const & v) const {
	return (left -> isBoundVar(v)) || (right -> isBoundVar(v));
}

ExpressionNode * OperatorNode::subst(VariableNode const & v, ExpressionNode const * e) {
	return new OperatorNode(op, left -> subst(v, e), right -> subst(v, e));
}
	
ProgramNode * OperatorNode::defun() const {
	return 0;
}

IntegerNode OperatorNode::deint() const {
	return IntegerNode(0, true);
}

ExpressionNode * OperatorNode::copy() const {
	return new OperatorNode(op, left -> copy(), right -> copy());
}

string OperatorNode::toString() const {
	stringstream s;
	string c;
	switch (op) {
		case _PLUS: c = "+"; break;
		case _MINUS: c = "-"; break;
		case _MULT: c = "*"; break;
		case _DIV: c = "/"; break;
		case _MOD: c = "%"; break;
		case _EQUAL: c = "="; break;
		case _LT: c = "<"; break;
		case _GT: c = ">"; break;
		case _LE: c = "<="; break;
		case _GE: c = ">="; break;
	}
	s << "(" << (left -> toString()) << " " << c << " " << (right -> toString()) << ")";
	return s.str();
}	
